// Reify allow us to load files that use 'import/export' syntax
// inside the node js environment
require('reify')

const express = require('express')
const { default: langs } = require('./i18n')
const { createBundleRenderer } = require('vue-server-renderer')
const fs = require('fs')
const path = require('path')

const isProd = process.env.NODE_ENV === 'production'
const resolve = file => path.resolve(__dirname, file)
const templatePath = resolve('./index.template.html')

// Create Express server app
const server = express()

// Vue bundle renderer
let renderer
// In development: wait for webpack compilation
// when receiving a SSR request
let readyPromise

if (isProd) {
  // In production: create server renderer using template and built server bundle.
  // The server bundle is generated by vue-ssr-webpack-plugin.
  const template = fs.readFileSync(templatePath, 'utf-8')
  const bundle = require('./dist/vue-ssr-server-bundle.json')
  // The client manifests are optional, but it allows the renderer
  // to automatically infer preload/prefetch links and directly add <script>
  // tags for any async chunks used during render, avoiding waterfall requests.
  const clientManifest = require('./dist/vue-ssr-client-manifest.json')
  renderer = createBundleRenderer(bundle, {
    runInNewContext: false,
    template,
    clientManifest,
  })
} else {
  // In development: setup the dev server with watch and hot-reload,
  // and create a new renderer on bundle / index template update.
  const setupDevServer = require('./server.dev')
  readyPromise = setupDevServer({
    server,
    templatePath,
    onUpdate: (bundle, options) => {
      // Re-create the bundle renderer
      renderer = createBundleRenderer(bundle, {
        runInNewContext: false,
        ...options,
      })
    },
  })
}

// Serve static files
const serve = (path, cache) => express.static(resolve(path), {
  maxAge: cache && isProd ? 1000 * 60 * 60 * 24 * 30 : 0,
})

// Serve dist files
server.use('/dist', serve('./dist', true))

// Render the Vue app using the bundle renderer
function renderApp (req, res) {
  const context = {
    url: req.url,
    // Languages sent by the browser
    locale: req.acceptsLanguages(langs) || 'en',
  }
  renderer.renderToString(context, (err, html) => {
    if (err) {
      // Render Error Page or Redirect
      res.status(500).send('500 | Internal Server Error')
      console.error(`error during render : ${req.url}`)
      console.error(err.stack)
    }
    res.send(html)
  })
}

// Process SSR requests
let ssr
if (isProd) {
  ssr = renderApp
} else {
  // In development: wait for webpack compilation
  // when receiving a SSR request
  ssr = (req, res) => {
    readyPromise.then(() => renderApp(req, res))
  }
}
server.get('*', ssr)

// Listening
const port = process.env.PORT || 8080
server.listen(port, () => {
  console.log(`server started at localhost:${port}`)
})
